use std::collections::VecDeque;

pub fn convert_base(num_str: &str, to_base: u32) -> String {
    // `num_str` is in the format `src(radix)`
    // Split it with '(' to get the `src` part and the `radix)` part
    let (src, radix_src) = num_str.split_once('(').unwrap();

    // Get the final `radix` value
    let radix = radix_src[..radix_src.len() - 1].parse::<u32>().unwrap();

    // Convert `src` to `u32`
    let n = from_str_radix(src, radix);

    // Convert `n` to `String` with `to_base` as the radix
    to_string_radix(n, to_base)
}

fn from_str_radix(src: &str, radix: u32) -> u32 {
    // `src` is a string of digits, which are all ASCII characters
    // so we can iterate over the byte slice of `src`
    let digits = src.as_bytes();

    let mut result = 0;

    for &c in digits {
        // Shift the result to the left by one digit
        result *= radix;

        // Convert the digit to a number
        let x = (c as char).to_digit(radix).unwrap();

        // Add the digit to the result
        result += x;
    }

    result
}

fn to_string_radix(mut num: u32, radix: u32) -> String {
    let mut result = VecDeque::new();

    while num > 0 {
        // Get the least significant digit of `num`.
        let digit = num % radix;
        num /= radix;
        // Add the digit to the front of `result`.
        result.push_front(
            // Digit is always an ASCII character, so we can safely convert it to `u8`
            char::from_digit(digit, radix).unwrap() as u8,
        );
    }

    // Convert `VecDeque<u8>` to `Vec<u8>`, then to `String`.
    // SAFETY: Since we know that all elements in `result` are ASCII characters,
    // we can safely convert it to `String` without checking the UTF-8 validity.
    unsafe {
        String::from_utf8_unchecked(
            // Make `result` contiguous, then convert it to `Vec<u8>`
            result.make_contiguous().to_vec(),
        )
    }
}
